﻿#pragma once

#include "../../src/config/box_config.hh"

namespace kratos {
namespace service {
class ServiceBox;
}
} // namespace kratos

namespace kratos {
namespace config {

/**
 * ServiceBox配置器.
 */
class BoxConfigImpl : public BoxConfig {
  using StringList = std::vector<std::string>;
  using StringMap = std::unordered_map<std::string, std::string>;
  using ReloadListenerMap = std::unordered_map<std::string, ReloadListener>;

  std::string logger_config_line_{"console://;line=[%y%m%d-%H:%M:%S:%U];flush=true"}; ///< 默认日志配置

  service::ServiceBox*             box_{nullptr};                           ///< 服务容器
  std::string                      config_file_path_;                       ///< 配置文件路径
  StringList                       listener_list_;                          ///< 监听器列表
  std::string                      finder_type_{"zookeeper"};               ///< 服务发现类型
  std::string                      finder_hosts_;                           ///< 服务发现远程主机
  std::time_t                      service_finder_connect_timeout_{5000};   ///< 服务发现连接超时
  StringList                       necessary_service_;                      ///< 容器所依赖的必需服务
  int                              connect_other_box_timeout_{5000};        ///< 连接其他容器超时
  std::unique_ptr<kconfig::Config> config_{nullptr};                        ///< 内部配置组件
  int                              box_channel_recv_buffer_len_{1024 * 16}; ///< 容器管道读缓冲长度
  std::string                      box_name_{"box"};                        ///< 容器名称，影响PID文件名
  std::string                      service_dir_{"service"};                 ///< 本地服务的存储目录
  StringMap                        service_map_;                            ///< 需要加载的本地服务名
  bool                             is_open_coroutine_{true};                ///< 是否对本地服务的调用开启协程
  ReloadListenerMap                reload_listener_map_;                    ///< 配置重载监听器
  std::string                      remote_service_repo_version_api_;        ///< 远程服务仓库版本API
  std::string                      remote_service_repo_latest_version_api_; ///< 远程服务仓库最新版本API
  std::string                      remote_service_repo_dir_;                ///< 远程服务仓库下载路径
  bool                             is_open_remote_update_{false};           ///< 是否开启远程更新
  int                              remote_repo_check_interval_{60};         ///< 远程仓库检查周期,秒
  bool                             is_start_as_daemon_{false};              ///< 是否以守护进程方式启动
  int                              http_max_call_timeout_{5};               ///< HTTP调用最大超时时间,秒
  bool                             is_open_rpc_stat_{false};                ///< 是否开启RPC统计

public:
  /**
   * 构造.
   *
   */
  BoxConfigImpl(kratos::service::ServiceBox *box);
  /**
   * 析构.
   *
   */
  virtual ~BoxConfigImpl();
  /**
   * 加载配置.
   * @param config_file_path 配置文件路径
   * @param [OUT] error 错误
   * @retval true 成功
   * @retval false 失败
   */
  auto load(const std::string &config_file_path, std::string &error) -> bool;
  /**
   * 重新加载配置.
   * @param config_file_path 配置文件路径
   * @param [OUT] error 错误
   * @retval true 成功
   * @retval false 失败
   */
  auto reload(const std::string &config_file_path, std::string &error) -> bool;
  /**
   * 设置一个监听回调，监听配置重载事件
   *
   * \param name 监听器名称
   * \param listener 监听回调
   * \retval true 成功
   * \return false 失败
   */
  auto add_reload_listener(const std::string &name, ReloadListener listener)
      -> bool;
  /**
   * 删除新加载事件监听器.
   *
   * \param name 监听器名称
   * \retval true 成功
   * \return false 失败
   */
  auto remove_reload_listener(const std::string &name) -> bool;
  /**
   * 获取配置器指针，用于获取自定义配置.
   *
   * \return 配置器指针
   */
  auto get_config_ptr() -> kconfig::Config *;
  /**
   * \brief 取得网络监听器列表, 例如:"127.0.0.1:12345"
   * \return 网络监听器列表
   */
  auto get_listener_list() const -> const std::vector<std::string> &;
  /**
   * 获取服务发现节点类型.
   *
   * \return 服务发现节点类型
   */
  auto get_service_finder_type() const -> const std::string &;
  /**
   * 获取服务发现主机地址列表.
   *
   * \return 服务发现主机地址列表
   */
  auto get_service_finder_hosts() const -> const std::string &;
  /**
   * 获取服务发现节点连接超时，毫秒.
   *
   * \return 服务发现节点连接超时，毫秒
   */
  auto get_service_finder_connect_timeout() const ->std::time_t;
  /**
   * 设置服务发现节点连接超时，毫秒.
   *
   * \param timeout 服务发现节点连接超时，毫秒
   */
  auto set_service_finder_connect_timeout(std::time_t timeout) const -> void;
  /**
   * 获取必须的服务名列表.
   *
   * \return 必须的服务名列表
   */
  auto get_necessary_service() const -> const std::vector<std::string> &;
  /**
   * 获取连接其他服务容器超时，秒.
   *
   * \return 连接其他服务容器超时，秒.
   */
  auto get_connect_other_box_timeout() const -> int;
  /**
   * 获取管道接收缓冲区长度，字节.
   *
   * \return 管道接收缓冲区长度，字节.
   */
  auto get_box_channel_recv_buffer_len() const -> int;
  /**
   * 获取服务容器名.
   *
   * \return 服务容器名.
   */
  auto get_box_name() const -> const std::string &;
  /**
   * 获取日志配置.
   *
   * \return 日志配置.
   */
  auto get_logger_config_line() const -> const std::string &;
  /**
   * 获取本地服务目录.
   *
   * \return 本地服务目录.
   */
  auto get_service_dir() const -> const std::string &;
  /**
   * 获取需要加载的本地服务表,{UUID,服务名}.
   *
   * \return 本地服务表,{UUID,服务名}.
   */
  auto get_preload_service() const
      -> const std::unordered_map<std::string, std::string> &;
  /**
   * 是否开启协程.
   *
   * \return true或者false
   */
  auto is_open_coroutine() const -> bool;
  /**
   * 获取远程组件仓库版本文件API.
   *
   * \return 远程组件仓库版本文件API.
   */
  auto get_remote_service_repo_version_api() const -> const std::string &;
  /**
   * 获取远程仓库API.
   *
   * \return 远程仓库API.
   */
  auto get_remote_service_repo_dir() const -> const std::string &;
  /**
   * 获取远程组件仓库最新版本文件API.
   *
   * \return 远程组件仓库最新版本文件API.
   */
  auto get_remote_service_repo_latest_version_api() const
      -> const std::string &;
  /**
   * 是否检查远程仓库组件更新.
   *
   * \return true或者false
   */
  auto is_open_remote_update() const -> bool;
  /**
   * 获取远程仓库检查周期，秒.
   *
   * \return 远程仓库检查周期，秒.
   */
  auto get_remote_repo_check_interval() const -> int;
  /**
   * 是否启动为守护进程.
   *
   * \return true或者false
   */
  auto is_start_as_daemon() const -> bool;
  /**
   * 获取HTTP调用超时时间,秒.
   *
   * \return HTTP调用超时时间,秒.
   */
  virtual auto get_http_max_call_timeout() const -> int;
  /**
   * 是否开启RPC信息统计.
   *
   * \return true或者false
   */
  virtual auto is_open_rpc_stat() -> bool;
  /**
   * 检测属性是否存在.
   * 
   * \param name 属性名
   * \return true或false
   */
  virtual auto has_attribute(const std::string &name) -> bool;

public:
  /**
   * 获取配置文件路径.
   *
   * \return 配置文件路径
   */
  auto get_config_file_path() const -> const std::string &;

  /**
   * 设置服务发现节点连接超时，毫秒.
   * \param timeout 超时, 秒
   */
  auto set_service_finder_connect_timeout(int timeout) -> void;

  /**
   * 设置连接其他服务容器超时，毫秒.
   * \param timeout 超时, 秒
   */
  auto set_connect_other_box_timeout(int timeout) -> void;

  /**
   * 设置网络读缓冲区长度,字节.
   * \param len 缓冲区长度
   */
  auto set_box_channel_recv_buffer_len(int len) -> void;

  /**
   * 设置HTTP调用/请求超时，
   * \param timeout 超时, 秒
   */
  auto set_http_max_call_timeout(int timeout) -> void;

  /**
   * 设置自动更新 
   */
  auto set_is_open_remote_update(bool on_off) -> void;
  /**
   * 设置RPC统计开关
   */
  auto set_is_open_rpc_stat(bool value) -> void;
  /**
   * 设置远程更新检查周期，秒 
   */
  auto set_remote_repo_check_interval(int second) -> void;
  /**
   * @brief 拷贝数据属性
   * @param rht 配置实例
   * @return 
  */
  auto copy_attribute(const BoxConfigImpl& rht)->void;

protected:
  auto operator=(BoxConfigImpl &&rht) noexcept -> const BoxConfigImpl &;
  /**
   * 调用配置重载监听器.
   *
   * \param config 新配置
   * \return
   */
  auto call_reload_listener(const BoxConfigImpl &config) -> void;
};

} // namespace config
} // namespace kratos
